﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Nito.AsyncEx;
using System;
using System.Threading.Tasks;

namespace EasyAdmin.Web.Authorizations
{
    /// <summary>
    /// 动态策略提供器
    /// </summary>
    public class AppAuthorizationPolicyProvider : IAuthorizationPolicyProvider
    {
        /// <summary>
        /// 异步锁
        /// </summary>
        private static readonly AsyncLock _mutex = new();
        
        /// <summary>
        /// 认证选项
        /// </summary>
        private readonly AuthorizationOptions _authorizationOptions;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="options"></param>
        public AppAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options)
        {
            BackupPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
            _authorizationOptions = options.Value;
        }

        /// <summary>
        ///默认回退策略
        /// </summary>
        private DefaultAuthorizationPolicyProvider BackupPolicyProvider { get; }

        /// <summary>
        /// 获得策略
        /// </summary>
        /// <param name="policyName"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public async Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
        {
            AuthorizationPolicy policy = null;
            if (!string.IsNullOrWhiteSpace(policyName) && policyName.StartsWith(AppAuthorizeAttribute.PolicyPrefix)) {
                using (await _mutex.LockAsync())
                {  
                    if (AppAuthorizeAttribute.TryGetPermissions(policyName, out var permissions))
                    {
                        var builder = new AuthorizationPolicyBuilder();
                        builder.Requirements.Add(new AppRequirement(permissions));
                        policy = builder.Build();
                        _authorizationOptions.AddPolicy(policyName, policy);
                        return policy;
                    }
                }
            }
            policy = await BackupPolicyProvider.GetPolicyAsync(policyName);
            if (policy is not null)
            {
                return policy;
            }
            return null;            
        }

        /// <summary>
        /// 获取默认策略
        /// </summary>
        /// <returns></returns>
        public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
        {
            return BackupPolicyProvider.GetDefaultPolicyAsync();
        }

        /// <summary>
        /// 获取回退策略
        /// </summary>
        /// <returns></returns>
        public Task<AuthorizationPolicy> GetFallbackPolicyAsync()
        {
            return BackupPolicyProvider.GetFallbackPolicyAsync();
        }
    }
}
